/// 多任务
pub mod tasks;
use super::encode::auto_decode;
use crate::AnyRes;
use serde::{de, Deserialize, Serialize};
use std::{
  collections::HashMap,
  ffi::OsStr,
  path::{Path, PathBuf},
  process::{Command, ExitStatus, Stdio},
};
use strum::*;
type DWORD = u32;

/// 日志R<...>R解析
#[cfg(feature = "regex")]
pub mod rlog;
/// 无首选 NUMA 节点
pub const NUMA_NO_PREFERRED_NODE: DWORD = 0x0;
/// Windows 创建无窗口进程的标志
pub const CREATE_NO_WINDOW: DWORD = 0x08000000;
/// Windows 创建新进程组的标志
pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
/// 调试新进程。调试器将接收所有调试事件，包括来自此进程创建的所有子进程的事件
pub const DEBUG_PROCESS: DWORD = 0x00000001;
/// 调试此进程。调试器不会接收此进程创建的任何子进程的调试事件
pub const DEBUG_ONLY_THIS_PROCESS: DWORD = 0x00000002;
/// 进程的主线程以挂起状态创建，直到调用 ResumeThread 函数
pub const CREATE_SUSPENDED: DWORD = 0x00000004;
/// 对于控制台进程，新进程没有访问其父进程控制台的权限
pub const DETACHED_PROCESS: DWORD = 0x00000008;
/// 新进程有一个新的控制台，而不是继承其父进程的控制台
pub const CREATE_NEW_CONSOLE: DWORD = 0x00000010;
/// 进程具有正常优先级类
pub const NORMAL_PRIORITY_CLASS: DWORD = 0x00000020;
/// 进程具有空闲优先级类
pub const IDLE_PRIORITY_CLASS: DWORD = 0x00000040;
/// 进程具有高优先级类
pub const HIGH_PRIORITY_CLASS: DWORD = 0x00000080;
/// 进程具有实时优先级类
pub const REALTIME_PRIORITY_CLASS: DWORD = 0x00000100;
/// 如果在 lpEnvironment 参数中指定了环境块，则它使用 Unicode 字符
pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400;
/// 新进程在单独的 Windows VDM 中运行 16 位应用程序
pub const CREATE_SEPARATE_WOW_VDM: DWORD = 0x00000800;
/// 新进程与其他应用程序共享 Windows VDM
pub const CREATE_SHARED_WOW_VDM: DWORD = 0x00001000;
/// 强制在单独的 VDM 中运行
pub const CREATE_FORCEDOS: DWORD = 0x00002000;
/// 进程具有低于正常优先级的优先级类
pub const BELOW_NORMAL_PRIORITY_CLASS: DWORD = 0x00004000;
/// 进程具有高于正常优先级的优先级类
pub const ABOVE_NORMAL_PRIORITY_CLASS: DWORD = 0x00008000;
/// 进程继承其父进程的处理器关联性
pub const INHERIT_PARENT_AFFINITY: DWORD = 0x00010000;
/// 进程继承其调用者的优先级
pub const INHERIT_CALLER_PRIORITY: DWORD = 0x00020000;
/// 进程是受保护的进程
pub const CREATE_PROTECTED_PROCESS: DWORD = 0x00040000;
/// 进程创建时使用扩展的启动信息
pub const EXTENDED_STARTUPINFO_PRESENT: DWORD = 0x00080000;
/// 开始后台模式，这可能会降低进程的内存和 I/O 优先级
pub const PROCESS_MODE_BACKGROUND_BEGIN: DWORD = 0x00100000;
/// 结束后台模式，恢复正常优先级
pub const PROCESS_MODE_BACKGROUND_END: DWORD = 0x00200000;
/// 进程不受其父作业的限制
pub const CREATE_BREAKAWAY_FROM_JOB: DWORD = 0x01000000;
/// 保留进程的代码授权级别
pub const CREATE_PRESERVE_CODE_AUTHZ_LEVEL: DWORD = 0x02000000;
/// 进程不继承其父进程的错误模式
pub const CREATE_DEFAULT_ERROR_MODE: DWORD = 0x04000000;
/// 为用户启用分析
pub const PROFILE_USER: DWORD = 0x10000000;
/// 为内核启用分析
pub const PROFILE_KERNEL: DWORD = 0x20000000;
/// 为服务器启用分析
pub const PROFILE_SERVER: DWORD = 0x40000000;
/// 忽略系统默认优先级和调度量程
pub const CREATE_IGNORE_SYSTEM_DEFAULT: DWORD = 0x80000000;

/// 表示命令执行结果的结构体
/// 这个结构体包含了命令执行后的标准输出、退出状态和标准错误输出。
#[derive(Debug, Clone)]
pub struct CmdOutput {
  /// 命令的标准输出，已经被解码为字符串
  pub stdout: String,
  /// 命令的退出状态
  pub status: ExitStatus,
  /// 命令的标准错误输出，保持为原始字节
  pub stderr: Vec<u8>,
}

/// 通用命令结果结构体，可序列化和反序列化
/// 这个结构体用于表示一个通用的命令执行结果，包含内容、状态和自定义选项。
/// 它可以被序列化和反序列化，方便在不同的上下文中传递和存储。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CmdResult<T> {
  /// 命令执行的结果内容
  pub content: String,
  /// 命令执行的状态，true 表示成功，false 表示失败
  pub status: bool,
  /// 与命令相关的自定义选项，类型为泛型 T
  pub opts: T,
}

impl<T> CmdResult<T> {
  /// 设置选项
  pub fn set_opts(mut self, opts: T) -> Self {
    self.opts = opts;
    self
  }

  /// 合并另一个 CmdResult
  pub fn merge(mut self, target: Self) -> Self {
    self.content = target.content;
    self.status = target.status;
    self
  }

  /// 设置状态
  pub fn set_status(mut self, state: bool) -> Self {
    self.status = state;
    self
  }

  /// 设置内容
  pub fn set_content(mut self, content: String) -> Self {
    self.content = content;
    self
  }

  /// 获取选项引用
  pub fn opts(&self) -> &T {
    &self.opts
  }
}

impl<'a, T: de::Deserialize<'a>> CmdResult<T> {
  /// 从字符串解析 CmdResult
  pub fn from_str(value: &'a str) -> crate::AnyResult<Self> {
    let s = value.trim().trim_start_matches("R<").trim_end_matches(">R");
    Ok(serde_json::from_str(s)?)
  }
}

impl<T: Serialize> CmdResult<T> {
  /// 将 CmdResult 转换为字符串
  pub fn to_str(&self) -> crate::AnyResult<String> {
    Ok(format!("R<{}>R", serde_json::to_string(self)?))
  }

  /// 将 CmdResult 转换为格式化的字符串
  pub fn to_string_pretty(&self) -> crate::AnyResult<String> {
    Ok(format!("R<{}>R", serde_json::to_string_pretty(self)?))
  }
}

/// 打开文件或目录的 shell 命令
#[cfg(feature = "fs")]
pub fn shell_open(target: impl AsRef<str>) -> crate::AnyResult<()> {
  let pathname = crate::fs::convert_path(target.as_ref());
  #[cfg(target_os = "macos")]
  Cmd::new("open").args(&["-R", &pathname]).spawn()?;
  #[cfg(target_os = "windows")]
  Cmd::new("explorer").arg(pathname).spawn()?;
  #[cfg(target_os = "linux")]
  Cmd::new("xdg-open").arg(pathname).spawn()?;
  Ok(())
}

/// 异步打开文件或目录的 shell 命令
#[cfg(all(feature = "fs", feature = "tokio"))]
pub async fn a_shell_open(target: impl AsRef<str>) -> crate::AnyResult<()> {
  let pathname = crate::fs::convert_path(target.as_ref());
  #[cfg(target_os = "macos")]
  Cmd::new("open").args(&["-R", &pathname]).a_spawn()?.wait().await?;
  #[cfg(target_os = "windows")]
  Cmd::new("explorer").arg(pathname).a_spawn()?.wait().await?;
  #[cfg(target_os = "linux")]
  Cmd::new("xdg-open").arg(pathname).a_spawn()?.wait().await?;
  Ok(())
}

/// 命令结构体，用于构建和执行系统命令
/// ```rust
/// use e_utils::{shell_open, Cmd};
/// fn test_cmd() {
///   let output = Cmd::new("echo Hello from cmd").output().unwrap();
///   assert_eq!(output.stdout, "Hello from cmd");
///   assert!(Cmd::new("echo Hello from cmd")
///     .output()
///     .is_err());
/// }
/// fn test_shell_open_windows() {
///   assert!(shell_open("C:\\").is_ok());
/// }
/// fn main() {
///   test_cmd();
///   test_shell_open_windows();
/// }
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Cmd {
  exe: String,
  args: Vec<String>,
  cwd: Option<PathBuf>,
  flags: DWORD,
  env: Option<HashMap<String, String>>,
  exe_type: ExeType,
}
impl Cmd {
  /// 获取自动识别的exe路径
  pub fn get_exe_path(&self) -> PathBuf {
    let cwd = self.cwd.clone().unwrap_or(std::env::current_dir().unwrap_or_default());
    cwd.join(&self.exe)
  }
  /// 检查exe路径是否存在
  pub fn check_exe_path(&self) -> crate::Result<PathBuf> {
    let path = self.get_exe_path();
    if !path.exists() {
      return Err(format!("File not found: {}", path.display()).into());
    }
    Ok(path)
  }
  /// Args处理
  pub fn split_args(args: &str, key: char) -> Vec<String> {
    let mut result = Vec::with_capacity(args.split_whitespace().count());
    let mut start = 0;
    let mut in_quotes = None;
    let chars: Vec<_> = args.chars().collect();
    for (i, &c) in chars.iter().enumerate() {
      match c {
        '"' | '\'' => {
          if let Some(quote) = in_quotes {
            if quote == c {
              in_quotes = None;
              if start < i {
                result.push(chars[start..i].iter().collect());
                start = i + 1;
              }
            }
          } else {
            in_quotes = Some(c);
            start = i + 1;
          }
        }
        _ if c == key && in_quotes.is_none() => {
          if start < i {
            result.push(chars[start..i].iter().collect());
          }
          start = i + 1;
        }
        _ if i == chars.len() - 1 => {
          if start <= i {
            result.push(chars[start..=i].iter().collect());
          }
        }
        _ => {}
      }
    }

    result
  }
}
impl Cmd {
  /// 获取flags
  pub fn get_flags(&self) -> DWORD {
    self.flags
  }
  /// 获取环境变量
  pub fn get_env(&self) -> Option<&HashMap<String, String>> {
    self.env.as_ref()
  }
  /// 获取工作目录
  pub fn get_cwd(&self) -> Option<&PathBuf> {
    self.cwd.as_ref()
  }
  /// 获取exe
  pub fn get_exe(&self) -> &str {
    &self.exe
  }
  /// 获取args
  pub fn get_args(&self) -> &Vec<String> {
    &self.args
  }
  /// 获取exe类型
  pub fn get_exe_type(&self) -> &ExeType {
    &self.exe_type
  }
}
impl Cmd {
  /// 默认的进程创建标志
  ///
  /// 包含以下标志位:
  /// - CREATE_UNICODE_ENVIRONMENT: 使用 Unicode 环境变量
  /// - CREATE_NEW_PROCESS_GROUP: 创建新的进程组
  /// - NORMAL_PRIORITY_CLASS: 使用正常优先级
  /// - INHERIT_PARENT_AFFINITY: 继承父进程的处理器关联性
  /// - INHERIT_CALLER_PRIORITY: 继承调用者的优先级
  /// - CREATE_PRESERVE_CODE_AUTHZ_LEVEL: 保留代码授权级别
  #[cfg(debug_assertions)]
  pub const DEFAULT_PROCESS_FLAGS: DWORD =
    CREATE_UNICODE_ENVIRONMENT | NORMAL_PRIORITY_CLASS | INHERIT_PARENT_AFFINITY | INHERIT_CALLER_PRIORITY | CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
  #[cfg(not(debug_assertions))]
  pub const DEFAULT_PROCESS_FLAGS: DWORD = CREATE_UNICODE_ENVIRONMENT
    | NORMAL_PRIORITY_CLASS
    | CREATE_NO_WINDOW
    | INHERIT_PARENT_AFFINITY
    | INHERIT_CALLER_PRIORITY
    | CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
  /// 命令结构体，用于构建和执行系统命令
  /// ```rust
  /// use e_utils::{shell_open, Cmd};
  /// fn test_cmd() {
  ///   let output = Cmd::new("echo Hello from cmd").output().unwrap();
  ///   assert_eq!(output.stdout, "Hello from cmd");
  ///   assert!(Cmd::new("echo Hello from cmd")
  ///     .output()
  ///     .is_err());
  /// }
  /// fn test_shell_open_windows() {
  ///   assert!(shell_open("C:\\").is_ok());
  /// }
  /// fn main() {
  ///   test_cmd();
  ///   test_shell_open_windows();
  /// }
  /// ```
  pub fn new<S: AsRef<OsStr>>(exe: S) -> Self {
    Self {
      exe: exe.as_ref().to_string_lossy().into_owned(),
      args: Vec::new(),
      cwd: None,
      flags: Self::DEFAULT_PROCESS_FLAGS,
      env: None,
      exe_type: ExeType::default(),
    }
  }
  /// 添加工作目录并更新 PATH 环境变量
  pub fn cwd(mut self, env_path: impl AsRef<std::path::Path>) -> Self {
    let path = env_path.as_ref().to_path_buf();
    self.cwd = Some(path.clone());

    // 获取或创建环境变量 map
    let env = self.env.get_or_insert_with(|| std::env::vars().collect());

    // 更新 PATH 环境变量
    Self::update_path_env(env, path);
    self
  }

  /// 更新环境变量中的 PATH
  fn update_path_env(env: &mut HashMap<String, String>, new_path: PathBuf) {
    // 使用 entry API 处理 Path 环境变量
    env.entry("Path".to_string()).and_modify(|path_str| {
      let mut paths = std::env::split_paths(path_str).collect::<Vec<_>>();
      // 添加新路径
      paths.push(new_path.clone());

      // 尝试合并路径并更新环境变量
      if let Ok(new_path_str) = std::env::join_paths(paths) {
        if let Ok(path_string) = new_path_str.into_string() {
          *path_str = path_string;
        }
      }
    });
  }
  /// 添加单个参数
  pub fn arg(mut self, arg: impl Into<String>) -> Self {
    let arg = arg.into();
    if !arg.is_empty() {
      self.args.push(arg);
    }
    self
  }
  /// 配置flags
  pub fn flags(mut self, flags: DWORD) -> Self {
    self.flags = flags;
    self
  }
  /// 添加多个参数
  pub fn args<I, S>(mut self, args: I) -> Self
  where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
  {
    self.args.extend(args.into_iter().map(|s| s.as_ref().to_string_lossy().into_owned()));
    self
  }
  /// 添加多个参数
  pub fn set_args(&mut self, args: Vec<String>) -> &mut Self {
    if !args.is_empty() {
      self.args = args;
    }
    self
  }

  /// 设置单个环境变量
  pub fn env<K, V>(mut self, key: K, val: V) -> Self
  where
    K: Into<String>,
    V: Into<String>,
  {
    self.env.get_or_insert_with(HashMap::new).insert(key.into(), val.into());
    self
  }

  /// 设置多个环境变量
  pub fn envs<I, K, V>(mut self, vars: I) -> Self
  where
    I: IntoIterator<Item = (K, V)>,
    K: Into<String>,
    V: Into<String>,
  {
    let env = self.env.get_or_insert_with(HashMap::new);
    for (key, val) in vars {
      env.insert(key.into(), val.into());
    }
    self
  }
  /// 设置是否使用 cmd.exe 或 sh
  pub fn set_type(mut self, exe_type: ExeType) -> Self {
    self.exe_type = exe_type;
    self
  }

  /// 准备标准 Command
  fn prepare_command(&self) -> crate::Result<Command> {
    self.prepare_generic_command(|cmd| Box::new(Command::new(cmd)))
  }

  /// 准备 Tokio Command
  #[cfg(feature = "tokio")]
  fn prepare_tokio_command(&self) -> crate::Result<tokio::process::Command> {
    self.prepare_generic_command(|cmd| Box::new(tokio::process::Command::new(cmd)))
  }

  /// 通用命令准备函数
  fn prepare_generic_command<C>(&self, new_command: impl Fn(&str) -> Box<C>) -> crate::Result<C>
  where
    C: CommandTrait,
  {
    let exe_type = match self.exe_type {
      ExeType::AutoShell => match ExeType::from_target(&self.exe) {
        v => v,
      },
      other => other,
    };
    let mut cmd = match exe_type {
      ExeType::AutoShell => return Err("AutoShell 无法执行".into()),
      ExeType::PowerShell => new_command("powershell").args(["-NoProfile", "-Command", &self.exe]),
      ExeType::Shell => new_command("sh").args(["-c", &self.exe]),
      ExeType::Cmd => new_command("cmd").args(["/C", &self.exe]),
      ExeType::Ps1Script => new_command("powershell").args(["-ExecutionPolicy", "Bypass", "-File", &self.exe]),
      ExeType::Vbs => new_command("cscript").args(["/Nologo"]).arg(&self.exe),
      ExeType::PythonScript => new_command("python").arg(&self.exe),
      ExeType::MacOSApp => new_command("open").arg(&self.get_exe_path()),
      ExeType::AndroidApk => new_command("adb").args(["shell", "am", "start", "-n", &self.exe]),
      ExeType::IosApp => new_command("xcrun").args(["simctl", "launch", "booted", &self.exe]),
      ExeType::Unknown => *new_command(&self.exe),
      _ => *new_command(&self.check_exe_path()?.to_string_lossy()),
    };
    // 如果参数不为空，则将exe作为参数
    if !self.args.is_empty() {
      cmd = cmd.args(&self.args);
    }
    // 设置环境变量
    if let Some(ref env) = self.env {
      cmd = cmd.envs(env);
    } else {
      cmd = cmd.envs(std::env::vars());
    }

    // 设置工作目录
    if let Some(ref cwd) = self.cwd {
      cmd = cmd.current_dir(cwd);
    }

    cmd = cmd.creation_flags(self.flags);
    // 配置标准输入输出
    cmd = cmd.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
    Ok(cmd)
  }

  /// 执行命令并等待结果
  pub fn output(&self) -> crate::Result<CmdOutput> {
    let output = self.prepare_command()?.output().any()?;
    let stdout = auto_decode(&output.stdout).unwrap_or_else(|_| String::from_utf8_lossy(&output.stdout).to_string());

    Ok(CmdOutput {
      stdout,
      status: output.status,
      stderr: output.stderr,
    })
  }

  /// 异步执行命令并等待结果
  #[cfg(feature = "tokio")]
  pub async fn a_output(&self) -> crate::Result<CmdOutput> {
    let output = self.prepare_tokio_command()?.output().await.any()?;
    let stdout = auto_decode(&output.stdout).unwrap_or_else(|_| String::from_utf8_lossy(&output.stdout).to_string());

    Ok(CmdOutput {
      stdout,
      status: output.status,
      stderr: output.stderr,
    })
  }

  /// 启动命令但不等待结果
  pub fn spawn(&self) -> crate::Result<std::process::Child> {
    self.prepare_command()?.spawn().any()
  }

  /// 异步启动命令但不等待结果
  #[cfg(feature = "tokio")]
  pub fn a_spawn(&self) -> crate::Result<tokio::process::Child> {
    self.prepare_tokio_command()?.spawn().any()
  }
}

/// 统一 Command 和 tokio::process::Command 接口的 trait
/// 这个 trait 定义了一组通用的命令配置方法，使得 std::process::Command 和 tokio::process::Command
/// 可以使用相同的接口进行操作。
pub trait CommandTrait<Target = Command> {
  /// 添加单个命令行参数
  fn arg<S: AsRef<OsStr>>(self, arg: S) -> Self;

  /// 添加多个命令行参数
  fn args<I, S>(self, args: I) -> Self
  where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>;

  /// 设置环境变量
  fn envs<I, K, V>(self, vars: I) -> Self
  where
    I: IntoIterator<Item = (K, V)>,
    K: AsRef<OsStr>,
    V: AsRef<OsStr>;
  /// 设置命令的工作目录
  fn current_dir<P: AsRef<std::path::Path>>(self, dir: P) -> Self;

  /// 配置命令的标准输入
  fn stdin<T: Into<Stdio>>(self, cfg: T) -> Self;

  /// 配置命令的标准输出
  fn stdout<T: Into<Stdio>>(self, cfg: T) -> Self;

  /// 配置命令的标准错误输出
  fn stderr<T: Into<Stdio>>(self, cfg: T) -> Self;

  /// 设置进程创建标志（主要用于 Windows 系统）
  fn creation_flags(self, flags: u32) -> Self;
}

// 为 std::process::Command 实现 CommandTrait
impl CommandTrait for Command {
  fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {
    Command::arg(&mut self, arg);
    self
  }
  fn args<I, S>(mut self, args: I) -> Self
  where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
  {
    Command::args(&mut self, args);
    self
  }
  fn envs<I, K, V>(mut self, vars: I) -> Self
  where
    I: IntoIterator<Item = (K, V)>,
    K: AsRef<OsStr>,
    V: AsRef<OsStr>,
  {
    Command::env_clear(&mut self).envs(vars);
    self
  }
  fn current_dir<P: AsRef<std::path::Path>>(mut self, dir: P) -> Self {
    Command::current_dir(&mut self, dir);
    self
  }
  fn stdin<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    Command::stdin(&mut self, cfg);
    self
  }
  fn stdout<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    Command::stdout(&mut self, cfg);
    self
  }
  fn stderr<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    Command::stderr(&mut self, cfg);
    self
  }

  fn creation_flags(mut self, flags: u32) -> Self {
    #[cfg(target_os = "windows")]
    {
      // 在非 Windows 系统上不执行任何操作
      std::os::windows::process::CommandExt::creation_flags(&mut self, flags);
    }
    self
  }
}

// 为 tokio::process::Command 实现 CommandTrait
#[cfg(feature = "tokio")]
impl CommandTrait for tokio::process::Command {
  fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {
    tokio::process::Command::arg(&mut self, arg);
    self
  }
  fn args<I, S>(mut self, args: I) -> Self
  where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
  {
    tokio::process::Command::args(&mut self, args);
    self
  }
  fn envs<I, K, V>(mut self, vars: I) -> Self
  where
    I: IntoIterator<Item = (K, V)>,
    K: AsRef<OsStr>,
    V: AsRef<OsStr>,
  {
    tokio::process::Command::env_clear(&mut self).envs(vars);
    self
  }
  fn current_dir<P: AsRef<std::path::Path>>(mut self, dir: P) -> Self {
    tokio::process::Command::current_dir(&mut self, dir);
    self
  }
  fn stdin<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    tokio::process::Command::stdin(&mut self, cfg);
    self
  }
  fn stdout<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    tokio::process::Command::stdout(&mut self, cfg);
    self
  }
  fn stderr<T: Into<Stdio>>(mut self, cfg: T) -> Self {
    tokio::process::Command::stderr(&mut self, cfg);
    self
  }
  fn creation_flags(mut self, flags: u32) -> Self {
    #[cfg(target_os = "windows")]
    tokio::process::Command::creation_flags(&mut self, flags);
    self
  }
}

/// 应用程序类型枚举
#[allow(missing_docs)]
#[derive(Default, Clone, Copy, Debug, Display, PartialEq, EnumString, VariantArray, Deserialize, Serialize)]
#[repr(i32)]
pub enum ExeType {
  #[default]
  #[strum(to_string = "Auto")]
  AutoShell,
  #[strum(to_string = "PS1")]
  PowerShell,
  #[strum(to_string = "SH")]
  Shell,
  #[strum(to_string = "CMD")]
  Cmd,
  #[strum(to_string = ".exe")]
  WindowsExe,
  #[strum(to_string = ".sh")]
  ShellScript,
  #[strum(to_string = ".ps1")]
  Ps1Script,
  #[strum(to_string = ".bat")]
  Bat,
  #[strum(to_string = ".vbs")]
  Vbs,
  #[strum(to_string = ".py")]
  PythonScript,
  #[strum(to_string = ".cmd")]
  CmdScript,
  #[strum(to_string = ".app")]
  MacOSApp,
  #[strum(to_string = ".LinuxEXE")]
  LinuxExe,
  #[strum(to_string = ".apk")]
  AndroidApk,
  #[strum(to_string = ".ipa")]
  IosApp,
  #[strum(to_string = ".so")]
  So,
  #[strum(to_string = ".dll")]
  Dll,
  #[strum(to_string = "Unknown")]
  Unknown,
}
impl ExeType {
  /// 从目标路径推断可执行文件类型
  pub fn from_target(p: impl AsRef<Path>) -> Self {
    match p.as_ref().extension().and_then(|x| x.to_str()).unwrap_or_default().to_lowercase().as_str() {
      "exe" => ExeType::WindowsExe,
      "bat" => ExeType::Bat,
      "cmd" => ExeType::CmdScript,
      "vbs" => ExeType::Vbs,
      "ps1" => ExeType::Ps1Script,
      "sh" => ExeType::ShellScript,
      "app" => ExeType::MacOSApp,
      "apk" => ExeType::AndroidApk,
      "ipa" => ExeType::IosApp,
      "py" => ExeType::PythonScript,
      "so" => ExeType::So,
      "dll" => ExeType::Dll,
      _ => ExeType::Unknown,
    }
  }
  /// 获取可执行文件类型的扩展名
  pub fn to_extension(&self) -> &'static str {
    match self {
      ExeType::WindowsExe => "exe",
      ExeType::Bat => "bat",
      ExeType::CmdScript => "cmd",
      ExeType::Vbs => "vbs",
      ExeType::Ps1Script => "ps1",
      ExeType::ShellScript => "sh",
      ExeType::MacOSApp => "app",
      ExeType::AndroidApk => "apk",
      ExeType::IosApp => "ipa",
      ExeType::PythonScript => "py",
      ExeType::So => "so",
      ExeType::Dll => "dll",
      _ => "",
    }
  }
}

#[cfg(test)]
mod tests {
  #[cfg(feature = "tokio")]
  mod a_async {
    use crate::{
      cmd::{Cmd, ExeType},
      fs::a_temp_file,
    };
    #[tokio::test]
    #[cfg(not(target_os = "windows"))]
    fn test_shell_open_unix() {
      assert!(a_shell_open("/").await.is_ok());
    }
    #[tokio::test]
    #[cfg(target_os = "windows")]
    async fn test_shell_open_windows() {
      use crate::cmd::a_shell_open;

      assert!(a_shell_open("C:\\").await.is_ok());
    }
    #[tokio::test]
    async fn test_cmd_bat() {
      let temp_dir = a_temp_file("test_cmd_bat", "test.bat", "echo test").await.unwrap();
      let cwd = temp_dir.parent().unwrap();
      let output = Cmd::new("test.bat").cwd(cwd).a_output().await.unwrap();
      assert!(output.stdout.contains("test"));
    }

    #[tokio::test]
    async fn test_cmd_type() {
      assert!(Cmd::new("echo Hello from cmd").set_type(ExeType::Cmd).output().is_ok());
      assert!(Cmd::new("echo Hello from cmd").set_type(ExeType::AutoShell).output().is_ok());
      assert!(Cmd::new("echo").args(["Hello", "from", "cmd"]).set_type(ExeType::IosApp).output().is_err());
      assert!(Cmd::new("echo Hello from cmd").set_type(ExeType::WindowsExe).output().is_err());
    }
    #[tokio::test]
    async fn test_cmd_zh() {
      let output = Cmd::new("echo 你好Rust").a_output().await.unwrap();
      assert_eq!(output.stdout, "你好Rust");
    }
  }
  mod sync {
    use crate::{
      cmd::{shell_open, Cmd, CmdResult},
      fs::temp_file,
    };
    use serde::{Deserialize, Serialize};
    #[test]
    #[cfg(target_os = "windows")]
    fn test_shell_open_windows() {
      assert!(shell_open("C:\\").is_ok());
    }
    #[test]
    #[cfg(not(target_os = "windows"))]
    fn test_shell_open_unix() {
      assert!(shell_open("/").is_ok());
    }
    #[test]
    fn test_cmd() {
      let output = Cmd::new("echo").args(["\"Hello from cmd\""]).output().unwrap();
      assert_eq!(output.stdout, "Hello from cmd");
    }

    #[test]
    fn test_cmd_result_serialization() {
      #[derive(Debug, Serialize, Deserialize)]
      struct TestOpts {
        value: String,
      }

      let result = CmdResult {
        content: "Test content".to_string(),
        status: true,
        opts: TestOpts { value: "test".to_string() },
      };

      let serialized = result.to_str().unwrap();
      assert!(serialized.starts_with("R<") && serialized.ends_with(">R"));

      let deserialized: CmdResult<TestOpts> = CmdResult::from_str(&serialized).unwrap();
      assert_eq!(deserialized.content, "Test content");
      assert_eq!(deserialized.status, true);
      assert_eq!(deserialized.opts.value, "test");
    }
    #[test]
    fn test_cmd_bat() {
      let temp_dir = temp_file("test_cmd_bat", "test.bat", "echo test").unwrap();
      let cwd = temp_dir.parent().unwrap();
      let output = Cmd::new("test.bat").cwd(cwd).output().unwrap();
      assert!(output.stdout.contains("test"));
    }
  }
}
